/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.aop.asm;

import cn.easyplatform.aop.AbstractClassAgent;
import cn.easyplatform.aop.ClassDefiner;
import cn.easyplatform.aop.MethodInterceptor;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Mirror;
import cn.easyplatform.org.objectweb.asm.Opcodes;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a>
 */
public class AsmClassAgent extends AbstractClassAgent {

    static int CLASS_LEVEL = Opcodes.V1_5;

    static final String MethodArray_FieldName = "_$$Easyplatform_methodArray";
    static final String MethodInterceptorList_FieldName = "_$$Easyplatform_methodInterceptorList";

    static {
        if (Lang.isJDK6())
            CLASS_LEVEL = Opcodes.V1_6;
    }

    @SuppressWarnings("unchecked")
    protected <T> Class<T> generate(ClassDefiner cd, Pair2[] pair2s,
                                    String newName, Class<T> klass, Constructor<T>[] constructors) {
        try {
            return (Class<T>) cd.load(newName);
        } catch (ClassNotFoundException e) {
        }
        Method[] methodArray = new Method[pair2s.length];
        List<MethodInterceptor>[] methodInterceptorList = new List[pair2s.length];
        for (int i = 0; i < pair2s.length; i++) {
            Pair2 pair2 = pair2s[i];
            methodArray[i] = pair2.method;
            methodInterceptorList[i] = pair2.listeners;
        }
        byte[] bytes = ClassY.enhandClass(klass, newName, methodArray,
                constructors);
        // Files.write(new File(newName), bytes);
        Class<T> newClass = (Class<T>) cd.define(newName, bytes);
        try {
            Mirror<T> mirror = Mirror.me(newClass);
            mirror.setValue(null, MethodArray_FieldName, methodArray);
            mirror.setValue(null, MethodInterceptorList_FieldName,
                    methodInterceptorList);
        } catch (Throwable e) {
        }
        return newClass;
    }

}
